package com.wg.net.server.tcp.handle;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wg.game.app.BaseApplication;
import com.wg.net.DisconnectReason;
import com.wg.net.NettyAttributeKey;
import com.wg.net.server.tcp.TcpSessionCache;
import com.wg.net.session.TcpSession;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.io.IOException;

/**
 * 服务器端基础处理器（抽象类，定义TCP/WebSocket连接的通用处理逻辑）
 * <p>
 * 职责：
 * - 管理会话生命周期（创建、缓存、销毁）
 * - 处理连接激活、异常断开等通用事件
 * - 分发接收到的数据包到业务逻辑
 *
 * @param <T> 业务数据类型（如ByteBuf、WebSocketFrame）
 * @author 少爷123
 */
public abstract class AbstractServerHandler<T> extends SimpleChannelInboundHandler<T> {
    private static final Log log = LogFactory.get();

    /**
     * 连接激活时创建会话并缓存
     *
     * @param channel 当前连接通道
     */
    public final void channelActive(Channel channel) {
        TcpSession session = createSession(channel);
        TcpSessionCache.getInstance().addPeer(session);
        log.debug("连接激活，创建会话并缓存 | 通道={}", channel.id());
    }

    /**
     * 异常捕获（统一处理连接异常）
     *
     * @param ctx   通道上下文
     * @param cause 异常原因
     */
    @Override
    public final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("连接发生异常 | 通道={}", ctx.channel().id(), cause);

        if (cause instanceof IOException) {
            log.warn("连接正常关闭（IO异常） | 通道={}", ctx.channel().id());
            return;
        }

        // 非IO异常：标记断开原因并关闭连接
        ctx.channel().attr(NettyAttributeKey.DISCONNECT_REASON).setIfAbsent(DisconnectReason.ExceptionDisconnect);
        ctx.close();
    }

    /**
     * 分发数据包到业务逻辑（核心方法）
     *
     * @param ctx  通道上下文
     * @param data 接收到的数据（字节数组）
     */
    protected final void dispatchPacket(ChannelHandlerContext ctx, byte[] data) {
        Channel channel = ctx.channel();
        String channelId = channel.id().asLongText();
        TcpSession session = TcpSessionCache.getInstance().get(channelId);

        if (session == null) {
            log.warn("会话不存在，关闭连接 | 通道ID={}", channelId);
            ctx.channel().attr(NettyAttributeKey.DISCONNECT_REASON)
                    .setIfAbsent(DisconnectReason.SessionNotExist);
            ctx.close();
            return;
        }

        try {
            if (session.getUserData() == null) {
                BaseApplication.INST.onInit(session, data);
            } else {
                BaseApplication.INST.onReceive(session, session.getUserData(), data); 
            }
        } catch (Exception e) {
            log.error("业务逻辑处理异常 | 通道ID={}", channelId, e);
            ctx.close();
        }
    }

    /**
     * 创建会话（抽象方法，子类实现具体逻辑）
     *
     * @param channel 当前连接通道
     * @return 会话对象
     */
    protected abstract TcpSession createSession(Channel channel);
}